/*
 * Copyright (c) 2018-2023 北京华恒盛世科技有限公司
 * QUICKPOOL is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
*/

#include "subcmd.h"

static json *jobgroup_2json(struct QuickPoolJobGroup *);
static void listjobgroup_usage(const char *);

/**
 * @brief       qp job group handler, to query job group from js.
 *
 * @param[in]   argc          #1: number of input argument
 * @param[in]   argv          #2: string array of the input argument
 *
 * @retval      0             #1: succeed
 * @retval      1             #2: input option is wrong or kind of input argument not specified
 * @retval      2             #3: argument has syntax error
 * @retval      3             #4: failed to query job group
 * @retval      4             #5: not enough memory to print json string
 */
int
cmd_list_jobgroups(int argc, char **argv)
{
    while (TRUE) {
        int option_index = 0;
        static struct option long_options[] = {
            {"help", no_argument, 0, 'h'},
            {NULL, 0, 0, 0}
        };

        int opt;
        opt = getopt_long(argc, argv, "h", long_options, &option_index);
        if (-1 == opt) {
            break;
        }

        switch (opt) {
        case 'h':
            listjobgroup_usage(argv[0]);
            exit(0);
        case '?':
        default:
            listjobgroup_usage(argv[0]);
            exit(1);
        }
    }

    // if not specify a job group path, set all to TRUE
    int num = 0;
    char **groups=NULL, **groupPoint=NULL;
    int all;
    num = get_argument_names(argc, argv, optind, &groups, &all, "job_group");
    if (0 < num) {
        groupPoint = groups;
    }

    int i;
    for (i=0; i<num; i++) {

        if ('/' != groups[i][0]) {

            fprintf(stderr, "Bad job group name <%s>. Must specify full path of job group name.\n",
                    groups[i]);
            FREEUP(groups);
            exit(2);
        }
    }

    struct request jobgroupReq;
    memset(&jobgroupReq, 0, sizeof(struct request));

    if (0 == num || NULL == groupPoint) {

        jobgroupReq.number = 1;
        jobgroupReq.keyvalues = (struct keyvalue *)calloc(1, sizeof(struct keyvalue));
        if (NULL == jobgroupReq.keyvalues) {
            fprintf(stderr, "calloc(%ld) failed due to %m.\n",
                    jobgroupReq.number*sizeof(struct keyvalue));
            exit(4);
        }

        jobgroupReq.keyvalues[0].key = REQUEST_KEY_NUMBER;
        jobgroupReq.keyvalues[0].value = (char *)calloc(12, sizeof(char));
        if (NULL == jobgroupReq.keyvalues[0].value) {
            fprintf(stderr, "calloc(%d) failed due to %m.\n", 23);
            exit(4);
        }
        snprintf(jobgroupReq.keyvalues[0].value, 12, "%d", 0);
    } else {

        // to query specific job group.
        jobgroupReq.number = 2;
        jobgroupReq.keyvalues = (struct keyvalue *)calloc(2, sizeof(struct keyvalue));
        if (NULL == jobgroupReq.keyvalues) {
            fprintf(stderr, "calloc(%ld) failed due to %m.\n",
                    jobgroupReq.number*sizeof(struct keyvalue));
            exit(4);
        }

        jobgroupReq.keyvalues[0].key = REQUEST_KEY_NUMBER;
        jobgroupReq.keyvalues[0].value = (char *)calloc(12, sizeof(char));
        if (NULL == jobgroupReq.keyvalues[0].value) {
            fprintf(stderr, "calloc(%d) failed due to %m.\n", 23);
            exit(4);
        }
        snprintf(jobgroupReq.keyvalues[0].value, 12, "%d", num);

        jobgroupReq.keyvalues[1].key = REQUEST_KEY_NAMES;

        unsigned int size=0;
        for (i = 0; i < num; i++) {
            size += strlen(groupPoint[i]) + 1;
        }

        jobgroupReq.keyvalues[1].value = (char *)calloc(size, sizeof(char));
        if (NULL == jobgroupReq.keyvalues[1].value) {
            fprintf(stderr, "calloc(%d) failed due to %m.\n", size);
            exit(4);
        }

        for (i = 0; i < num; i++) {
			
            if (i == 0) {
                strcpy(jobgroupReq.keyvalues[1].value, groupPoint[i]);
            } else {
                strcat(jobgroupReq.keyvalues[1].value, " ");
                strcat(jobgroupReq.keyvalues[1].value, groupPoint[i]);
            }
        }
    }

    struct QuickPoolJobGroupReply *reply;
    reply = client_get_jobgroup(&jobgroupReq, NULL);
    FREEUP(groups);
    if (NULL == reply) {
        exit(3);
    }

    if (0 == reply->num_jobgroup) {

        fprintf(stderr, "No job groups yet in the system.\n");
        gf_xdr_free(libxdr_jobgroup_reply, reply);
        FREEUP(reply);

        exit(0);
    }

    json *jsonJobGroupList = json_CreateObject();
    unsigned int j;
    for (j=0; j<reply->num_jobgroup; j++) {

        json *jsonJobGroup = jobgroup_2json(&(reply->job_groups[j]));
        json_AddItemToObject(jsonJobGroupList, reply->job_groups[j].name, jsonJobGroup);
    }

    char *strJson;
    strJson = json_Print(jsonJobGroupList);
    if (NULL != strJson) {
        fprintf(stdout, "%s\n", strJson);
        FREEUP(strJson);
    } else {

        perror("malloc");
        json_Delete(jsonJobGroupList);
        gf_xdr_free(libxdr_jobgroup_reply, reply);
        FREEUP(reply);

        exit(4);
    }
    json_Delete(jsonJobGroupList);

    gf_xdr_free(libxdr_jobgroup_reply, reply);
    FREEUP(reply);

    exit(0);
} // end function cmd_list_jobgroups

/* ------------------------------------------------
 *
 *  below are static functions used in this file
 *
 * ------------------------------------------------ */

/**
 * @brief       transform job group to json.
 *
 * @param[in]   jobgroup      #1: job group being tranformed
 *
 * @retval      not NULL      #1: transformed json object
 */
static json *
jobgroup_2json(struct QuickPoolJobGroup *jobgroup)
{
    json *jsonJobGroup = json_CreateObject();

    s2j_json_set_basic_element(jsonJobGroup, jobgroup, string, "GROUP", path);

    s2j_json_set_basic_element(jsonJobGroup, jobgroup, int, "NJOBS", counts[JGRP_COUNT_NJOBS]);

    int numPend = jobgroup->counts[JGRP_COUNT_PEND] + jobgroup->counts[JGRP_COUNT_NPSUSP];
    json_AddNumberToObject(jsonJobGroup, "PEND", numPend);

    s2j_json_set_basic_element(jsonJobGroup, jobgroup, int, "RUN", counts[JGRP_COUNT_NRUN]);
    s2j_json_set_basic_element(jsonJobGroup, jobgroup, int, "SSUSP", counts[JGRP_COUNT_NSSUSP]);
    s2j_json_set_basic_element(jsonJobGroup, jobgroup, int, "USUSP", counts[JGRP_COUNT_NUSUSP]);
    s2j_json_set_basic_element(jsonJobGroup, jobgroup, int, "EXIT", counts[JGRP_COUNT_NEXIT]);
    s2j_json_set_basic_element(jsonJobGroup, jobgroup, int, "DONE", counts[JGRP_COUNT_NDONE]);

    if (jobgroup->max_jobs < INFINIT_INT) {
        s2j_json_set_basic_element(jsonJobGroup, jobgroup, int, "JLIMIT", max_jobs);
    }

    return jsonJobGroup;
} // end function jobgroup_2json

static void
listjobgroup_usage(const char *cmd)
{
    fprintf(stdout, "qp job %s usage: [-h, --help] [job_group_name]\n", cmd);

    return;
}
